<?php

/*
 * Copyright (C) 2009 - 2011 Pham Cong Dinh
 *
 * This file is part of Spica.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

// namespace spica\core;

/**
 * The SpicaServiceFactory is an abstract class that provides a factory
 * for the creation of instances of service class.
 *
 * This abstract class follows the abstract static factory design pattern.
 * This enables a Spica based appication to create a service class in a portable
 * manner without using the constructor of the Service implementation class.
 *
 * This class is dependent on Base.php so please add
 *   <code>include_once 'library/spica/core/Base.php';</code>
 * before using it.
 *
 * @category   spica
 * @package    core
 * @author     Pham Cong Dinh <pcdinh at phpvietnam dot net>
 * @since      Version 0.3
 * @since      May 21, 2009
 * @license    http://www.gnu.org/licenses/lgpl-3.0.txt
 * @version    $Id: ServiceFactory.php 1869 2011-01-07 18:55:25Z pcdinh $
 */
abstract class SpicaServiceFactory
{
    /**
     * Base path to service class files
     *
     * @var string
     */
    protected $_path;

    /**
     * Sets of data service connections.
     *
     * @var array
     */
    protected static $_services;

    /**
     * Constructs an object of <code>SpicaServiceFactory</code>.
     *
     * @param string $path Base path to service class files
     */
    public function __construct($path = null)
    {
        if (null === $path)
        {
            $path = SpicaContext::getAppPath().'/service';
        }

        $this->_path = $path;
    }

    /**
     * Creates an instance of a particular service class.
     *
     * @throws SpicaClassNotFoundException
     * @param  string $alias A datasource configuration entry
     * @param  string $namespace Subdirectory name in /service
     * @return object
     */
    public function create($alias, $namespace = '')
    {
        if (true === isset(self::$_services[$alias]))
        {
            return end(self::$_services[$alias]);
        }

        $factoryClass = get_class($this);
        $class        = str_replace('Factory', '', $factoryClass);

        if (true === class_exists($class, false))
        {
            return new $class($alias);
        }

        if (!empty($namespace))
        {
            $namespace = '/'.$namespace;
        }

        $path = $this->_path.$namespace.'/'.$class.'.php';

        $fp = fopen($path, 'r', true);
        
        if (false !== $fp)
        {
            fclose($fp);
            include $path;
        }

        if (false === class_exists($class, false))
        {
            include_once 'library/spica/core/Exception.php';
            throw new SpicaClassNotFoundException('Service class '.$class.' cannot be found at '.spica_path_make_relative($path));
        }

        return new $class($alias);
    }
}

?>